#include "taskQueue.h"
#include "threadPool.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

//静态函数的可见域是本文件
//向客户端发送命令结果
static int do_ls(pSession_t ps);
static int do_pwd(pSession_t ps);
static int do_cd(pSession_t ps, pCmd_t pcmd);
static int do_rm(pSession_t ps, pCmd_t pcmd);
static int do_mkdir(pSession_t ps, pCmd_t pcmd);
static int do_puts(pSession_t ps, pCmd_t pcmd);
static int do_gets(pSession_t ps, pCmd_t pcmd);
static int do_rmdir(pSession_t ps, pCmd_t pcmd);
//将文件类型从int转成char*
static void file_type(mode_t mode, char *type);

int send_data(int fd, const void *buf, size_t len) {
    size_t total_sent = 0;
    while (total_sent < len) {
        ssize_t sent = send(fd, (char *)buf + total_sent, len - total_sent, 0);
        if (sent <= 0) return -1; // 发送失败
        total_sent += sent;
    }
    return total_sent;
}

//线程清理函数
void clean_func(void *p)
{
    pTaskQueue_t pQue = (pTaskQueue_t)p;
    pthread_mutex_unlock(&pQue->mutex);
}

//子线程的具体工作，回应客户端发来的命令
void *child_handle(void *p)
{
    //参数是任务队列
    pTaskQueue_t pQue = (pTaskQueue_t)p;

    pTaskNode_t pCur = NULL;  //定义一个任务节点，用来接收任务
    pSession_t ps = (pSession_t)calloc(1, sizeof(Session_t)); //定义一个通信类型，用来传递客户端套接字和缓冲区
    getcwd(ps->cur_dir, sizeof(ps->cur_dir));
    int data_len = -1;  //数据长度
    Cmd_t cmd; //定义一个命令类型，用来接命令
    int ret = -1;

    while (1) {
        //从任务队列中取一个任务
        pthread_mutex_lock(&pQue->mutex);
        pthread_cleanup_push(clean_func, pQue);//线程清理
        if (0 == pQue->queueSize) {
            pthread_cond_wait(&pQue->cond, &pQue->mutex);//等待任务
        }
        //如果退出标志为1，退出线程
        if (1 == pQue->exitFlag) {
            printf("thread exit!\n");
            free(ps);
            ps = NULL;
            pthread_exit(NULL);
        }
        getTaskNode(pQue, &pCur);//得到任务
        pthread_mutex_unlock(&pQue->mutex);

        //处理任务
        ps->_sess_fd = pCur->_clifd;//设置客户端套接字
        printf("client connected...\n");
        while (1) {
            memset(ps->_sess_buf, 0, BUF_SIZE);
            memset(&cmd, 0, sizeof(Cmd_t));

            //先接收数据长度
            ret = recv(ps->_sess_fd, &data_len, sizeof(data_len), 0);
            if (0 == ret || 0 == data_len) {
                //对端已断开
                close(ps->_sess_fd);
                printf("client exit!\n");
                break;//此次任务结束，退出循环
            }

            //再接收具体的数据
            recv(ps->_sess_fd, ps->_sess_buf, data_len, 0);
            //从接收缓冲区中读取命令
            memcpy(&cmd, ps->_sess_buf, sizeof(Cmd_t));
            printCmd(&cmd);
            //判断是什么命令
            if (!strcmp("cd", cmd._cmd[0])) {
                do_cd(ps, &cmd);
            }
            else if (!strcmp("pwd", cmd._cmd[0])) {
                do_pwd(ps);
            }
            else if (!strcmp("ls", cmd._cmd[0])) {
                do_ls(ps);
            }
            else if (!strcmp("rm", cmd._cmd[0])) {
                do_rm(ps, &cmd);
            }
            else if (!strcmp("mkdir", cmd._cmd[0])) {
                do_mkdir(ps, &cmd);
            }
            else if (!strcmp("puts", cmd._cmd[0])) {
                do_puts(ps, &cmd);
            }
            else if (!strcmp("gets", cmd._cmd[0])) {
                do_gets(ps, &cmd);
            }
            else if (!strcmp("rmdir", cmd._cmd[0])) {
                do_rmdir(ps, &cmd);
            }
            else {
                //非法命令
                continue;
            }
        }

		//释放任务
        free(pCur);
        pCur = NULL;
        pthread_cleanup_pop(1);//线程清理
    }
}

//将文件类型从int转成char*
static void file_type(mode_t mode, char *type)
{
    if (S_ISREG(mode)) {
        strncpy(type, "-", 1);
    }
    else if (S_ISDIR(mode)) {
        strncpy(type, "d", 1);
    }
    else if (S_ISFIFO(mode)) {
        strncpy(type, "p", 1);
    }
    else {
        strncpy(type, "o", 1);
    }
}

static int do_ls(pSession_t ps) {
    DIR *dirp = opendir(ps->cur_dir); // 打开会话当前目录
    if (!dirp) {
        int flag = -1;
        send(ps->_sess_fd, &flag, sizeof(flag), 0);
        return -1;
    }

    struct dirent *dir_info;
    int data_len = -1;
    char full_path[PATH_MAX];

    while ((dir_info = readdir(dirp))) {
        if (strcmp(dir_info->d_name, ".") == 0 || 
            strcmp(dir_info->d_name, "..") == 0) continue;

        // 构造完整路径
        snprintf(full_path, sizeof(full_path), "%.2048s/%.1024s", ps->cur_dir, dir_info->d_name);

        struct stat stat_info;
        memset(&stat_info, 0, sizeof(stat_info));
        stat(full_path, &stat_info); // 使用完整路径

        char type[2] = ""; // 注意：确保至少2字节空间
        file_type(stat_info.st_mode, type);

        memset(ps->_sess_buf, 0, BUF_SIZE);
        sprintf(ps->_sess_buf, "%-2s%-20s   %10ldB", type, dir_info->d_name, stat_info.st_size);

        data_len = strlen(ps->_sess_buf);
        send(ps->_sess_fd, &data_len, sizeof(data_len), 0);
        send(ps->_sess_fd, ps->_sess_buf, data_len, 0);
    }

    data_len = 0;
    send(ps->_sess_fd, &data_len, sizeof(data_len), 0);
    closedir(dirp);
    return 0;
}

static int do_pwd(pSession_t ps) {
    int data_len = strlen(ps->cur_dir);
    send(ps->_sess_fd, &data_len, sizeof(int), 0);
    send(ps->_sess_fd, ps->cur_dir, data_len, 0);
    return 0;
}

static int do_cd(pSession_t ps, pCmd_t pcmd) {
    if (pcmd->_argc < 2) {
        const char* msg = "Usage: cd <directory>";
        int len = strlen(msg);
        send(ps->_sess_fd, &len, sizeof(int), 0);
        send(ps->_sess_fd, msg, len, 0);
        return -1;
    }

    char target_dir[PATH_MAX];
    char resolved_path[PATH_MAX];

    // 构造目标路径
    if (pcmd->_cmd[1][0] == '/') {
        strncpy(target_dir, pcmd->_cmd[1], sizeof(target_dir));
    } else {
        snprintf(target_dir, sizeof(target_dir), "%.2048s/%.1024s", ps->cur_dir, pcmd->_cmd[1]);
    }

    // 解析规范路径
    if (!realpath(target_dir, resolved_path)) {
        const char* msg = "Directory does not exist";
        int len = strlen(msg);
        send(ps->_sess_fd, &len, sizeof(int), 0);
        send(ps->_sess_fd, msg, len, 0);
        return -1;
    }

    // 验证是否为目录
    struct stat statbuf;
    if (stat(resolved_path, &statbuf) || !S_ISDIR(statbuf.st_mode)) {
        const char* msg = "Not a directory";
        int len = strlen(msg);
        send(ps->_sess_fd, &len, sizeof(int), 0);
        send(ps->_sess_fd, msg, len, 0);
        return -1;
    }

    // 更新会话当前目录
    strncpy(ps->cur_dir, resolved_path, sizeof(ps->cur_dir));
    
    // 返回新目录
    int data_len = strlen(ps->cur_dir);
    send(ps->_sess_fd, &data_len, sizeof(int), 0);
    send(ps->_sess_fd, ps->cur_dir, data_len, 0);
    return 0;
}

static int do_rm(pSession_t ps, pCmd_t pcmd) {
    if (pcmd->_argc < 2) {
        const char* msg = "Usage: rm <filename>";
        int len = strlen(msg);
        send(ps->_sess_fd, &len, sizeof(int), 0);
        send(ps->_sess_fd, msg, len, 0);
        return -1;
    }

    char abs_path[PATH_MAX];
    snprintf(abs_path, sizeof(abs_path), "%.2048s/%.1024s", ps->cur_dir, pcmd->_cmd[1]);

    char result_buf[BUF_SIZE];
    if (unlink(abs_path) == 0) {
        snprintf(result_buf, sizeof(result_buf), "Removed %s", pcmd->_cmd[1]);
    } else {
        snprintf(result_buf, sizeof(result_buf), "Remove failed: %s", strerror(errno));
    }

    int data_len = strlen(result_buf);
    send(ps->_sess_fd, &data_len, sizeof(int), 0);
    send(ps->_sess_fd, result_buf, data_len, 0);
    return 0;
}

static int do_mkdir(pSession_t ps, pCmd_t pcmd) {
    if (pcmd->_argc < 2) {
        const char* msg = "Usage: mkdir <dirname>";
        int len = strlen(msg);
        send(ps->_sess_fd, &len, sizeof(int), 0);
        send(ps->_sess_fd, msg, len, 0);
        return -1;
    }

    char abs_path[PATH_MAX];
    snprintf(abs_path, sizeof(abs_path), "%.2048s/%.1024s", ps->cur_dir, pcmd->_cmd[1]);

    char result_buf[BUF_SIZE];
    if (mkdir(abs_path, 0775) == 0) {
        snprintf(result_buf, sizeof(result_buf), "Created %s", pcmd->_cmd[1]);
    } else {
        snprintf(result_buf, sizeof(result_buf), "Create failed: %s", strerror(errno));
    }

    int data_len = strlen(result_buf);
    send(ps->_sess_fd, &data_len, sizeof(int), 0);
    send(ps->_sess_fd, result_buf, data_len, 0);
    return 0;
}

// 删除空目录 (新增功能)
static int do_rmdir(pSession_t ps, pCmd_t pcmd) {
    if (pcmd->_argc < 2) {
        const char* msg = "Usage: rmdir <dirname>";
        int len = strlen(msg);
        send_data(ps->_sess_fd, &len, sizeof(int));
        send_data(ps->_sess_fd, msg, len);
        return -1;
    }

    char abs_path[PATH_MAX];
    snprintf(abs_path, sizeof(abs_path), "%.2048s/%.1024s", ps->cur_dir, pcmd->_cmd[1]);

    char result_buf[BUF_SIZE];
    if (rmdir(abs_path) == 0) {
        snprintf(result_buf, sizeof(result_buf), "Removed directory: %s", pcmd->_cmd[1]);
    } else {
        const char *error_msg = "";
        switch (errno) {
            case ENOTEMPTY:
                error_msg = "Directory not empty";
                break;
            case ENOENT:
                error_msg = "Directory does not exist";
                break;
            case ENOTDIR:
                error_msg = "Not a directory";
                break;
            case EACCES:
                error_msg = "Permission denied";
                break;
            default:
                error_msg = strerror(errno);
        }
        snprintf(result_buf, sizeof(result_buf), "Remove failed: %s", error_msg);
    }

    int data_len = strlen(result_buf);
    send_data(ps->_sess_fd, &data_len, sizeof(int));
    send_data(ps->_sess_fd, result_buf, data_len);
    return 0;
}

static int do_puts(pSession_t ps, pCmd_t pcmd)
{
    char abs_path[PATH_MAX];
    printf("before snprintf\n");
    snprintf(abs_path, sizeof(abs_path), "%.2048s/%.1024s", ps->cur_dir, pcmd->_cmd[1]);
    printf("after snprintf\n");
    printf("%s upload\n", abs_path);
    //客户端是上传，服务器是下载
    if (0 == download(ps->_sess_fd, abs_path)) {
        sprintf(ps->_sess_buf, "file [%s] upload succeed!", pcmd->_cmd[1]);
    }
    else {
        sprintf(ps->_sess_buf, "file [%s] upload failed!", pcmd->_cmd[1]);
    }
    int data_len = strlen(ps->_sess_buf);
    send(ps->_sess_fd, &data_len, sizeof(int), 0);
    send(ps->_sess_fd, ps->_sess_buf, data_len, 0);
    return 0;
}

static int do_gets(pSession_t ps, pCmd_t pcmd)
{
    char abs_path[PATH_MAX];
    snprintf(abs_path, sizeof(abs_path), "%.2048s/%.1024s", ps->cur_dir, pcmd->_cmd[1]);
    printf("%s download\n", abs_path);
    //客户端是下载，服务器是发送
    if (0 == upload(ps->_sess_fd, abs_path)) {
        sprintf(ps->_sess_buf, "file [%s] download succeed!", pcmd->_cmd[1]);
    }
    else {
        sprintf(ps->_sess_buf, "file [%s] download failed!", pcmd->_cmd[1]);
    }
    int data_len = strlen(ps->_sess_buf);
    send(ps->_sess_fd, &data_len, sizeof(int), 0);
    send(ps->_sess_fd, ps->_sess_buf, data_len, 0);
    return 0;
}

